package com.keith.jpa.tenant.context;

import com.alibaba.ttl.TransmittableThreadLocal;
import com.google.common.base.Strings;
import com.sun.istack.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * TenantContextHolder.java
 * 租户上下文
 *
 * @author czykeih
 * @version 1.0 2023/10/25
 */
@Component
public class TenantContextHolder implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    private static final ThreadLocal<Deque<UserTenant>> tenantLocal=new TransmittableThreadLocal<>();
    private static final ThreadLocal<String> tenantIdLocal=new TransmittableThreadLocal<>();
    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        synchronized (this) {
            if(TenantContextHolder.applicationContext != null){
                return;
            }
            TenantContextHolder.applicationContext = applicationContext;
        }
    }

    public static <T> T getBean(String name){
        try {
            return (T) applicationContext.getBean(name);
        }catch (Throwable e){
            return null;
        }
    }
    public static <T> T getBean(Class<T> className){
        try {
            return (T) applicationContext.getBean(className);
        }catch (Throwable e){
            return null;
        }
    }

    /**
     * 设置当前上下文租户ID
     */
    public static void setTenantId(String tenantId){
        tenantIdLocal.set(tenantId);
    }

    /**
     * 删除上下文租户id
     */
    public static void removeTenantId(){
        tenantIdLocal.remove();
    }

    /**
     * 获取上下文租户id
     */

    public static String getTenantId(){
        UserTenant userTenant=getTenant();
        if(userTenant!=null&&!Strings.isNullOrEmpty(userTenant.getTenantId())){
            return userTenant.getTenantId();
        }
        return tenantIdLocal.get();
    }

    /**
     * 获取当前租户设置
     */
    public static UserTenant getTenant(){
        Deque<UserTenant> userTenants = tenantLocal.get();
        if (userTenants == null) {
            return null;
        }
        return userTenants.peek();
    }

    public static void setTenant(UserTenant userTenant){
        Deque<UserTenant> userTenants = tenantLocal.get();
        if (userTenants == null) {
            userTenants = new ArrayDeque<>();
            tenantLocal.set(userTenants);
        }
        userTenants.push(userTenant);
    }

    public static void removeTenant(){
        Deque<UserTenant> userTenants = tenantLocal.get();
        if(userTenants!=null){
            userTenants.pop();
            if(userTenants.isEmpty()){
                tenantLocal.remove();
            }
        }else{
            tenantLocal.remove();
        }
    }
}
